﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace eWallet.Security.Cryptography
{
	/// <summary>
	/// Defines the interface for a module that provides encryption
	/// and decryption functionality.
	/// </summary>
	public interface ICryptoModule
	{

		/// <summary>
		/// Returns the mode of encryption the module can handle.
		/// </summary>
		EncryptionMethod EncryptionMethod { get; }

		/// <summary>
		/// Decrypts the given encrypted data.
		/// </summary>
		/// <param name="cipher">The encrypted data to decrypt.</param>
		byte[] Decrypt(byte[] cipher);

		/// <summary>
		/// Decrypts the data specified in <paramref name="cipher"/> and converts the decrypted
		/// data using the converter specified in <paramref name="outputConverter"/>.
		/// </summary>
		/// <typeparam name="TOutput">The type of the data to convert the decrypted data to.</typeparam>
		/// <param name="cipher">The encrypted data to decrypt.</param>
		/// <param name="outputConverter">A converter that can convert to the type specified in <typeparamref name="TOutput"/>.</param>
		TOutput Decrypt<TOutput>(byte[] cipher, Converter<byte[], TOutput> outputConverter);

		/// <summary>
		/// Decrypts the data from the stream specified in <paramref name="cipherStream"/>
		/// and stores the output in the stream specified in <paramref name="dataStream"/>.
		/// </summary>
		/// <param name="cipherStream">The stream containing the data to decrypt.</param>
		/// <param name="dataStream">The stream to write the decrypted data to.</param>
		void Decrypt(Stream cipherStream, Stream dataStream);

		/// <summary>
		/// Encrypts the given data.
		/// </summary>
		/// <param name="data">The data to encrypt.</param>
		byte[] Encrypt(byte[] data);

		/// <summary>
		/// Encrypts the data given in <paramref name="inputData"/> by first converting it to a byte array
		/// using the converter specified in <paramref name="inputConverter"/>.
		/// </summary>
		/// <typeparam name="TInput">The type of the input data.</typeparam>
		/// <param name="inputData">The data to convert and encrypt.</param>
		/// <param name="inputConverter">A converter that can convert from the type specified in <typeparamref name="TInput"/> to a byte array.</param>
		byte[] Encrypt<TInput>(TInput inputData, Converter<TInput, byte[]> inputConverter);

		/// <summary>
		/// Encrypts the data from the given stream (<paramref name="dataStream"/>) and
		/// writes it to the stream specified in <paramref name="cipherStream"/>.
		/// </summary>
		/// <param name="dataStream">The stream containing the data to encrypt.</param>
		/// <param name="cipherStream">The stream to write the encrypted data to.</param>
		void Encrypt(Stream dataStream, Stream cipherStream);

		/// <summary>
		/// When implemented in a class, returns a description that represents the data that is
		/// used to perform encryption and decryption in the crypto module, for instance a
		/// hash of that data.
		/// </summary>
		/// <remarks>
		/// This method must not return a string that can be used to reproduce the data that
		/// is used to encrypt and decrypt data with.
		/// </remarks>
		/// <returns></returns>
		string GetDescription();

	}
}
